🌐 JavaScript Browser BOM

Browser Object Model - Làm việc với trình duyệt

📚 Giới thiệu về BOM

BOM (Browser Object Model) là tập hợp các đối tượng JavaScript cho phép bạn tương tác với trình duyệt web. Khác với DOM (Document Object Model) chỉ làm việc với nội dung trang web, BOM cho phép bạn điều khiển toàn bộ cửa sổ trình duyệt.

🎯 BOM bao gồm:
  • window - Đối tượng chính của trình duyệt
  • location - Thông tin về URL hiện tại
  • history - Lịch sử duyệt web
  • navigator - Thông tin về trình duyệt
  • screen - Thông tin về màn hình

🪟 Window Object

window là đối tượng toàn cục (global object) trong JavaScript trình duyệt. Tất cả các biến và function global đều là thuộc tính của window.

� Thuộc tính Window chi tiết

Thuộc tính Mô tả Kiểu dữ liệu Miền giá trị
innerWidth Chiều rộng vùng nội dung cửa sổ (viewport) Number 0 - max screen width (px)
innerHeight Chiều cao vùng nội dung cửa sổ (viewport) Number 0 - max screen height (px)
outerWidth Chiều rộng toàn bộ cửa sổ (bao gồm border) Number 0 - screen width (px)
outerHeight Chiều cao toàn bộ cửa sổ (bao gồm toolbar) Number 0 - screen height (px)
scrollX Vị trí scroll ngang của document Number 0 - max scroll width (px)
scrollY Vị trí scroll dọc của document Number 0 - max scroll height (px)
screenX Vị trí X của cửa sổ trên màn hình Number -∞ to +∞ (px, có thể âm)
screenY Vị trí Y của cửa sổ trên màn hình Number -∞ to +∞ (px, có thể âm)
devicePixelRatio Tỷ lệ pixel vật lý/CSS pixel Number 0.5 - 5.0 (thường 1, 1.5, 2, 3)
closed Kiểm tra cửa sổ đã đóng chưa Boolean true | false
name Tên của cửa sổ (window target) String Bất kỳ string hợp lệ

�🔧 Thuộc tính kích thước quan trọng

Kích thước cửa sổ:

console.log("Chiều rộng:", window.innerWidth);
console.log("Chiều cao:", window.innerHeight);
console.log("Chiều rộng (bao gồm scrollbar):", window.outerWidth);
console.log("Chiều cao (bao gồm thanh công cụ):", window.outerHeight);

⚡ Methods của Window

Alert, Confirm, Prompt

// Hiển thị thông báo
alert("Xin chào!");

// Xác nhận
let result = confirm("Bạn có chắc?");

// Nhập liệu
let name = prompt("Tên của bạn?");

Open & Close Window

// Mở cửa sổ mới
let newWindow = window.open(
    "https://google.com",
    "_blank",
    "width=600,height=400"
);

// Đóng cửa sổ
newWindow.close();

Scroll Methods

// Cuộn đến vị trí
window.scrollTo(0, 500);

// Cuộn thêm
window.scrollBy(0, 100);

// Cuộn đến element
element.scrollIntoView();

📍 Location Object

window.location chứa thông tin về URL hiện tại và cho phép điều hướng trang.

🔍 Thuộc tính Location

Thuộc tính Mô tả Kiểu dữ liệu Miền giá trị/Ví dụ
href URL đầy đủ (có thể ghi) String https://example.com/page?id=1#section
protocol Giao thức URL (có thể ghi) String "http:", "https:", "ftp:", "file:"
host Hostname + port (có thể ghi) String "example.com:8080", "localhost:3000"
hostname Tên miền không có port (có thể ghi) String "example.com", "localhost", "192.168.1.1"
port Số port (có thể ghi) String "", "80", "443", "3000", "8080"
pathname Đường dẫn URL (có thể ghi) String "/", "/page", "/user/profile"
search Query string bao gồm ? (có thể ghi) String "", "?id=1", "?name=John&age=25"
hash Fragment bao gồm # (có thể ghi) String "", "#section", "#top", "#user-123"
origin Protocol + hostname + port (read-only) String "https://example.com", "http://localhost:3000"
💡 Lưu ý về Location properties:
  • Writable: Hầu hết thuộc tính có thể ghi → tự động chuyển hướng
  • origin: Read-only, được tính từ protocol + hostname + port
  • port: Trống ("") nếu dùng port mặc định (80 cho HTTP, 443 cho HTTPS)
  • search: Bao gồm dấu "?" đầu tiên
  • hash: Bao gồm dấu "#" đầu tiên

🚀 Methods của Location

1. location.href - Chuyển hướng với history

// Cách 1: Gán trực tiếp
location.href = "https://google.com";

// Cách 2: Sử dụng assign() (tương đương)
location.assign("https://google.com");

// Đều lưu trang hiện tại vào history (có thể back)

2. location.replace() - Thay thế không lưu history

// Thay thế trang hiện tại (KHÔNG lưu trong history)
location.replace("https://example.com");

// Người dùng KHÔNG thể back về trang này
// Thường dùng cho: login redirect, error pages
💡 Khác biệt:
  • href/assign: Lưu trang hiện tại → có thể Back
  • replace: Không lưu trang hiện tại → KHÔNG thể Back

3. location.reload() - Tải lại trang

// Tải lại trang (như nhấn F5)
location.reload();

// Tải lại trang từ server (bỏ qua cache)
location.reload(true);  // Deprecated trong HTML5

// Cách mới để force reload
location.reload(); // Browser tự quyết định cache
⚠️ Cảnh báo: Các button này sẽ tải lại trang thực tế!

4. So sánh các methods

Method Lưu History Có thể Back Khi nào dùng
location.href ✅ Có ✅ Có Navigation thông thường
location.assign() ✅ Có ✅ Có Tương đương href
location.replace() ❌ Không ❌ Không Login redirect, Error pages
location.reload() - - Refresh trang hiện tại

5. Ví dụ thực tế sử dụng

🔐 Scenario 1: Login thành công
function loginSuccess() {
    // Chuyển hướng đến dashboard
    // Người dùng có thể back về trang login
    location.href = "/dashboard";
}

// Sử dụng:
if (userCredentials.isValid) {
    loginSuccess();
}
⏰ Scenario 2: Session hết hạn
function sessionExpired() {
    // Thay thế trang hiện tại bằng login
    // KHÔNG cho phép back về trang cũ (bảo mật)
    location.replace("/login");
}

// Sử dụng:
if (sessionToken.isExpired()) {
    alert("Phiên đăng nhập đã hết hạn!");
    sessionExpired();
}
🔄 Scenario 3: Refresh dữ liệu
function refreshData() {
    // Tải lại trang để cập nhật dữ liệu mới
    location.reload();
}

// Sử dụng:
document.getElementById('refreshBtn').onclick = () => {
    if (confirm("Tải lại trang để cập nhật dữ liệu?")) {
        refreshData();
    }
};
🎛️ Scenario 4: Chuyển hướng thông minh
function smartRedirect(url, options = {}) {
    const { 
        replaceHistory = false, 
        confirm = true,
        message = "Chuyển hướng đến trang mới?"
    } = options;
    
    if (confirm && !window.confirm(message)) {
        return false;
    }
    
    if (replaceHistory) {
        location.replace(url);
    } else {
        location.href = url;
    }
    
    return true;
}

// Sử dụng:
// Chuyển hướng thông thường
smartRedirect("/profile");

// Chuyển hướng không lưu history
smartRedirect("/login", { 
    replaceHistory: true,
    message: "Về trang đăng nhập?" 
});
💡 Lưu ý khi sử dụng:
  • Login flow: Dùng href để user có thể back
  • Security redirect: Dùng replace để ngăn back
  • Data refresh: Dùng reload() khi cần dữ liệu mới
  • User experience: Luôn confirm trước khi redirect

🕐 History Object

window.history cho phép điều khiển lịch sử duyệt web của người dùng mà không cần tải lại trang.

📋 Thuộc tính và Methods của History

Thuộc tính/Method Mô tả Kiểu dữ liệu Miền giá trị/Tham số
length Số lượng entries trong history stack Number (read-only) 1 - không giới hạn
scrollRestoration Kiểm soát việc restore scroll position String "auto" | "manual"
state State object của history entry hiện tại Any (read-only) null | Object
back() Quay lại 1 trang trong history Method Không có tham số
forward() Tiến tới 1 trang trong history Method Không có tham số
go(delta) Di chuyển delta bước trong history Method delta: Number (-∞ to +∞)
pushState() Thêm entry mới vào history stack Method (state, title, url?)
replaceState() Thay thế entry hiện tại trong history Method (state, title, url?)

History Methods Demo:

// Quay lại trang trước
history.back();

// Tiến tới trang sau
history.forward();

// Di chuyển n trang (âm = quay lại, dương = tiến tới)
history.go(-2);  // Quay lại 2 trang
history.go(1);   // Tiến tới 1 trang

// Thêm state mới vào history (không tải lại trang)
history.pushState({page: 1}, "Title", "/page1");

// Thay thế state hiện tại
history.replaceState({page: 2}, "Title", "/page2");

🧭 Navigator Object

window.navigator chứa thông tin về trình duyệt và hệ điều hành của người dùng. Đây là một đối tượng chỉ đọc (read-only) cung cấp thông tin về môi trường trình duyệt.

📋 Thuộc tính Navigator chi tiết

Thuộc tính Mô tả Kiểu dữ liệu Miền giá trị
userAgent Chuỗi định danh trình duyệt và hệ điều hành String Text chứa browser/OS info
platform Nền tảng hệ điều hành String "Win32", "MacIntel", "Linux x86_64", etc.
language Ngôn ngữ ưa thích của trình duyệt String ISO language codes: "en-US", "vi-VN", etc.
languages Danh sách ngôn ngữ được hỗ trợ Array Array of language codes
onLine Trạng thái kết nối internet Boolean true (online) | false (offline)
cookieEnabled Cookie có được bật không Boolean true (enabled) | false (disabled)
hardwareConcurrency Số lõi CPU logic Number 1 - 128+ (hoặc undefined)
maxTouchPoints Số điểm chạm tối đa Number 0 (non-touch) - 10+ (multi-touch)
deviceMemory RAM thiết bị (GB) - Chrome/Edge only Number 0.25, 0.5, 1, 2, 4, 8 (max 8GB vì privacy)
connection Thông tin kết nối mạng Object NetworkInformation object
geolocation API lấy vị trí địa lý Object Geolocation object
permissions API kiểm tra quyền truy cập Object Permissions object
serviceWorker API đăng ký Service Worker Object ServiceWorkerContainer object
mediaDevices API truy cập camera/microphone Object MediaDevices object
clipboard API truy cập clipboard Object Clipboard object

🔍 Xem thông tin Navigator chi tiết:

// Thông tin cơ bản
console.log("User Agent:", navigator.userAgent);
console.log("Platform:", navigator.platform);
console.log("Ngôn ngữ:", navigator.language);
console.log("Trạng thái online:", navigator.onLine);

// Thông tin nâng cao  
console.log("Cookie enabled:", navigator.cookieEnabled);
console.log("Hardware concurrency:", navigator.hardwareConcurrency);
console.log("Max touch points:", navigator.maxTouchPoints);
console.log("Languages:", navigator.languages);

💡 Ứng dụng thực tế của Navigator

1. 🌍 Phát hiện ngôn ngữ và localization

function detectLanguage() {
    const userLang = navigator.language || navigator.userLanguage;
    const supportedLangs = navigator.languages || [userLang];
    
    console.log("Ngôn ngữ chính:", userLang);
    console.log("Danh sách ngôn ngữ:", supportedLangs);
    
    // Chọn ngôn ngữ phù hợp cho website
    if (userLang.startsWith('vi')) {
        return 'vietnamese';
    } else if (userLang.startsWith('en')) {
        return 'english';
    } else {
        return 'english'; // Default
    }
}

2. 📱 Phát hiện thiết bị và tối ưu UX

function detectDeviceCapabilities() {
    // Thu thập thông tin từ browser APIs
    const info = {
        isMobile: navigator.maxTouchPoints > 0,
        cpuCores: navigator.hardwareConcurrency || 'Unknown',
        platform: navigator.platform || 'Unknown',
        memoryGB: navigator.deviceMemory || 'N/A', // Chỉ Chrome/Edge
        userAgent: navigator.userAgent
    };
    
    // ⚠️ LƯU Ý QUAN TRỌNG:
    // Browser KHÔNG trả về thông tin hardware chính xác 100%
    // Ví dụ: Máy M4 Pro RAM 24GB có thể chỉ hiện 8GB hoặc N/A
    // Lý do: Privacy protection và security policies
    
    let platformDesc = 'Unknown';
    if (info.platform.includes('Mac')) {
        platformDesc = 'macOS';
        // Phát hiện Apple Silicon (M1, M2, M3, M4...)
        if (!info.userAgent.includes('Intel')) {
            platformDesc = 'macOS (Apple Silicon)';
        }
    }
    
    // KHUYẾN NGHỊ: Sử dụng feature detection thay vì hardware detection
    // ✅ Responsive design > device detection
    // ✅ Performance testing > specs checking
    
    return { platformDesc, ...info };
}

3. 🌐 Kiểm tra kết nối và offline mode

function setupOfflineMode() {
    // Kiểm tra trạng thái ban đầu
    updateConnectionStatus();
    
    // Lắng nghe sự kiện thay đổi kết nối
    window.addEventListener('online', () => {
        console.log("🌐 Đã kết nối internet");
        syncOfflineData(); // Đồng bộ dữ liệu offline
    });
    
    window.addEventListener('offline', () => {
        console.log("🔌 Mất kết nối internet");
        enableOfflineMode(); // Chuyển sang chế độ offline
    });
}
⚠️ Lưu ý quan trọng về Navigator:
  • UserAgent spoofing: Có thể bị giả mạo, không nên dựa vào 100%
  • Privacy: Một số thông tin có thể bị ẩn vì lý do bảo mật
  • Feature detection: Nên kiểm tra tính năng thay vì dựa vào browser name
  • Responsive design: Kết hợp với CSS media queries cho kết quả tốt nhất

🌍 Geolocation API

// Lấy vị trí hiện tại
navigator.geolocation.getCurrentPosition(
    function(position) {
        console.log("Latitude:", position.coords.latitude);
        console.log("Longitude:", position.coords.longitude);
        console.log("Accuracy:", position.coords.accuracy);
    },
    function(error) {
        console.log("Lỗi:", error.message);
        // Error codes:
        // 1: PERMISSION_DENIED
        // 2: POSITION_UNAVAILABLE  
        // 3: TIMEOUT
    },
    {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 60000
    }
);

⚠️ Lưu ý quan trọng:

  • HTTPS: Geolocation API chỉ hoạt động trên HTTPS hoặc localhost
  • Quyền truy cập: Trình duyệt sẽ hỏi quyền truy cập vị trí
  • Thời gian chờ: Có thể mất vài giây để lấy vị trí chính xác
  • Độ chính xác: Phụ thuộc vào thiết bị và kết nối
🧪 Demo Test (Không cần quyền truy cập)

Nếu không thể test với vị trí thật, hãy thử demo mô phỏng:

🖥️ Screen Object

window.screen chứa thông tin về màn hình của người dùng. Đây là đối tượng chỉ đọc (read-only) cung cấp thông tin về phần cứng màn hình và không liên quan đến cửa sổ trình duyệt.

📋 Thuộc tính Screen chi tiết

Thuộc tính Mô tả Kiểu dữ liệu Miền giá trị
width Chiều rộng màn hình vật lý Number 320 - 7680+ pixels (1366, 1920, 2560, 3840...)
height Chiều cao màn hình vật lý Number 240 - 4320+ pixels (768, 1080, 1440, 2160...)
availWidth Chiều rộng khả dụng (trừ taskbar) Number ≤ screen.width pixels
availHeight Chiều cao khả dụng (trừ taskbar) Number ≤ screen.height pixels
colorDepth Độ sâu màu (bits per pixel) Number 8, 16, 24, 32 bits (thường 24 hoặc 32)
pixelDepth Độ sâu pixel (bits per pixel) Number Thường bằng colorDepth (8, 16, 24, 32)
orientation Đối tượng orientation (mobile/tablet) Object ScreenOrientation object (có thể null)
orientation.type Kiểu hướng màn hình String "portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"
orientation.angle Góc xoay của màn hình Number 0, 90, 180, 270 degrees
availLeft Tọa độ X khả dụng đầu tiên Number 0+ pixels (multi-monitor)
availTop Tọa độ Y khả dụng đầu tiên Number 0+ pixels (có taskbar top)
💡 Giải thích miền giá trị:
  • Màu sắc: 24-bit = 16.7 triệu màu, 32-bit = + alpha channel
  • Orientation: Chỉ có trên thiết bị hỗ trợ xoay màn hình
  • Multi-monitor: availLeft/availTop có thể > 0 với nhiều màn hình
  • Retina/HiDPI: Có thể khác với CSS pixels do scaling

🔍 Xem thông tin Screen chi tiết:

// Kích thước màn hình vật lý
console.log("Độ phân giải màn hình:", screen.width + "x" + screen.height);

// Vùng làm việc (trừ taskbar)
console.log("Vùng làm việc:", screen.availWidth + "x" + screen.availHeight);

// Thông tin màu sắc
console.log("Độ sâu màu:", screen.colorDepth + " bits");
console.log("Độ sâu pixel:", screen.pixelDepth + " bits");

// Thông tin hướng màn hình (mobile)
console.log("Hướng màn hình:", screen.orientation?.type);
console.log("Góc xoay:", screen.orientation?.angle + "°");

💡 Ứng dụng thực tế của Screen Object

1. 📐 Phát hiện độ phân giải và tối ưu content

function getScreenCategory() {
    const width = screen.width;
    const height = screen.height;
    
    // Phân loại theo độ phân giải
    if (width >= 3840 && height >= 2160) {
        return "4K Ultra HD (3840x2160+)";
    } else if (width >= 2560 && height >= 1440) {
        return "2K/QHD (2560x1440+)";
    } else if (width >= 1920 && height >= 1080) {
        return "Full HD (1920x1080+)";
    } else if (width >= 1366 && height >= 768) {
        return "HD (1366x768+)";
    } else {
        return "Low Resolution";
    }
}

2. 🎨 Kiểm tra khả năng hiển thị màu

function analyzeColorCapability() {
    const colorDepth = screen.colorDepth;
    const pixelDepth = screen.pixelDepth;
    
    let colorInfo = {
        depth: colorDepth,
        totalColors: Math.pow(2, colorDepth),
        quality: ""
    };
    
    if (colorDepth >= 32) {
        colorInfo.quality = "Excellent (True Color + Alpha)";
    } else if (colorDepth >= 24) {
        colorInfo.quality = "Very Good (True Color)";
    } else if (colorDepth >= 16) {
        colorInfo.quality = "Good (High Color)";
    } else {
        colorInfo.quality = "Limited (256 colors or less)";
    }
    
    return colorInfo;
}

3. 📱 Theo dõi thay đổi orientation (Mobile)

function setupOrientationTracking() {
    // Kiểm tra hỗ trợ orientation
    if (screen.orientation) {
        console.log("Hướng hiện tại:", screen.orientation.type);
        console.log("Góc xoay:", screen.orientation.angle);
        
        // Lắng nghe thay đổi orientation
        screen.orientation.addEventListener('change', () => {
            console.log("Orientation changed to:", screen.orientation.type);
            updateLayoutForOrientation();
        });
    }
}

4. 📏 So sánh Screen vs Window sizes

function compareScreenVsWindow() {
    const comparison = {
        screen: {
            total: \`\${screen.width}x\${screen.height}\`,
            available: \`\${screen.availWidth}x\${screen.availHeight}\`
        },
        window: {
            inner: \`\${window.innerWidth}x\${window.innerHeight}\`,
            outer: \`\${window.outerWidth}x\${window.outerHeight}\`
        },
        taskbarSize: {
            horizontal: screen.width - screen.availWidth,
            vertical: screen.height - screen.availHeight
        }
    };
    
    return comparison;
}
💡 Khác biệt quan trọng:
  • screen.width/height: Kích thước màn hình vật lý (không đổi)
  • screen.availWidth/availHeight: Kích thước khả dụng (trừ taskbar)
  • window.innerWidth/innerHeight: Kích thước nội dung cửa sổ
  • window.outerWidth/outerHeight: Kích thước toàn bộ cửa sổ
⚠️ Lưu ý khi sử dụng Screen Object:
  • Chỉ đọc: Không thể thay đổi các thuộc tính của screen
  • Multi-monitor: Chỉ trả về thông tin màn hình chính
  • DPI scaling: Có thể ảnh hưởng đến giá trị pixel trả về
  • Privacy: Một số trình duyệt có thể hạn chế thông tin screen

⏰ Timing Functions

JavaScript cung cấp các function để thực thi code sau một khoảng thời gian nhất định hoặc lặp lại theo chu kỳ.

📋 Timing Functions chi tiết

Function Mô tả Tham số Trả về
setTimeout() Thực thi function sau delay time (callback, delay, ...args) Number (timeoutId)
clearTimeout() Hủy timeout chưa thực thi (timeoutId) undefined
setInterval() Thực thi function lặp lại theo chu kỳ (callback, interval, ...args) Number (intervalId)
clearInterval() Dừng interval đang chạy (intervalId) undefined
💡 Chi tiết tham số:
  • callback: Function cần thực thi (Function)
  • delay/interval: Thời gian ms (Number, min = 4ms trong HTML5)
  • ...args: Các tham số truyền cho callback (Any)
  • timeoutId/intervalId: Số ID để clear (Number > 0)
⚠️ Lưu ý quan trọng:
  • Minimum delay: HTML5 spec quy định min 4ms
  • Nested setTimeout: >= 5 lần lồng nhau → minimum 4ms
  • Background tabs: Throttled xuống còn 1000ms
  • Memory leaks: Luôn clear timeout/interval khi không dùng
  • this context: Arrow functions để giữ nguyên context

⚡ Demo Timing Functions

setTimeout & clearTimeout

// Thực thi sau 3 giây
let timeoutId = setTimeout(() => {
    console.log("Đã hết 3 giây!");
}, 3000);

// Hủy timeout
clearTimeout(timeoutId);

setInterval & clearInterval

// Thực thi mỗi giây
let intervalId = setInterval(() => {
    console.log("Tick!");
}, 1000);

// Hủy interval
clearInterval(intervalId);

🛠️ Ví dụ thực tế

🎯 Bài tập 1: Đồng hồ số

Tạo một đồng hồ hiển thị thời gian hiện tại và cập nhật mỗi giây.

💡 Hướng dẫn: HTML/CSS đã có sẵn, bạn chỉ cần viết JavaScript functions: startClock()stopClock()

🎯 Bài tập 2: URL Parser

Nhập một URL và phân tích các thành phần của nó.

💡 Hướng dẫn: HTML/CSS đã có sẵn, bạn chỉ cần viết JavaScript function: parseURL()

🎯 Bài tập 3: BOM Info Dashboard

Tạo dashboard hiển thị thông tin đầy đủ về Window, Location, Navigator, Screen.

🪟 Window Info
Chưa tải...
� Location Info
Chưa tải...
🧭 Navigator Info
🖥️ Screen Info
Chưa tải...
� Hướng dẫn: HTML/CSS đã có sẵn, bạn chỉ cần viết JavaScript function: loadBOMDashboard()

🎯 Bài tập 4: Responsive Detector

Phát hiện kích thước màn hình và hiển thị loại thiết bị.

💡 Hướng dẫn: HTML/CSS đã có sẵn, bạn chỉ cần viết JavaScript function: detectDevice()

🎯 Bài tập 5: Location Navigator

Tạo ứng dụng điều hướng với history management.

💡 Hướng dẫn: HTML/CSS đã có sẵn, bạn chỉ cần viết các JavaScript functions: navigateToUrl(), replaceUrl(), addToHistory()

✅ Best Practices

👍 Nên làm:

  • Luôn kiểm tra sự tồn tại của API trước khi sử dụng
  • Xử lý lỗi khi sử dụng Geolocation API
  • Sử dụng clearTimeoutclearInterval để tránh memory leak
  • Kiểm tra navigator.onLine trước khi thực hiện network request

⚠️ Không nên:

  • Lạm dụng alert(), confirm() vì làm gián đoạn UX
  • Mở quá nhiều cửa sổ popup
  • Sử dụng location.reload() không cần thiết
  • Dựa vào User Agent để detect browser (không chính xác)
  • Dựa vào hardware specs để tạo UI logic

🚨 Cảnh báo về Hardware Detection:

Tại sao browser không trả về thông tin hardware chính xác?

  • Privacy Protection: Các trình duyệt hạn chế thông tin để bảo vệ privacy
  • Fingerprinting Prevention: Ngăn chặn việc tracking user qua hardware
  • Security Policies: Web API có giới hạn an ninh

Ví dụ thực tế:

  • MacBook M4 Pro RAM 24GB → Browser báo cáo 8GB hoặc N/A
  • navigator.platform = "MacIntel" (không phải "M4 Pro")
  • navigator.deviceMemory bị giới hạn ở 8GB max

✅ Thay thế tốt hơn:

  • Responsive Design thay vì device detection
  • Performance testing thay vì specs checking
  • Progressive Enhancement cho tất cả devices
  • Feature Detection thay vì Hardware Detection

🔧 Hướng dẫn khắc phục sự cố

🚨 Các vấn đề thường gặp với Geolocation API:

1. 🔒 Lỗi HTTPS

Triệu chứng: "Geolocation API chỉ hoạt động trên HTTPS"

Giải pháp:

  • Sử dụng localhost cho việc phát triển: http://localhost
  • Deploy lên HTTPS khi production
  • Sử dụng ngrok hoặc các tunnel service cho testing
2. ❌ Lỗi quyền truy cập (PERMISSION_DENIED)

Triệu chứng: "Quyền truy cập bị từ chối"

Giải pháp:

  • Nhấp vào biểu tượng 🔒 bên trái thanh địa chỉ
  • Chọn "Cho phép" cho Location
  • Tải lại trang và thử lại
  • Kiểm tra cài đặt Privacy của trình duyệt
3. ⏰ Lỗi timeout

Triệu chứng: "Hết thời gian chờ"

Giải pháp:

  • Kiểm tra kết nối internet
  • Bật GPS trên thiết bị di động
  • Tăng giá trị timeout trong options
  • Thử lại ở vị trí khác có tín hiệu tốt hơn
4. 🌐 Lỗi vị trí không khả dụng

Triệu chứng: "Vị trí không khả dụng"

Giải pháp:

  • Kiểm tra GPS/Location services đã bật chưa
  • Thử trên thiết bị khác
  • Kiểm tra tường lửa/proxy có chặn không

✅ Tips để sử dụng Geolocation hiệu quả:

  • Luôn check hỗ trợ: if (navigator.geolocation)
  • Xử lý lỗi đầy đủ: 3 loại lỗi chính (permission, unavailable, timeout)
  • Tối ưu options: Balance giữa độ chính xác và thời gian
  • Fallback plan: Có phương án dự phòng khi Geolocation lỗi
  • User experience: Hiển thị loading và thông báo rõ ràng